package ckw.database.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PostLoad;
import javax.persistence.Transient;

import ckw.managers.ModulesManager;
import core.communication.message.NodeState;
import core.communication.message.NodeStateEnum;
import core.database.NodeType;

@Entity(name = "ckw.Node")
public class Node extends core.database.Node implements Serializable {
	private static final long	serialVersionUID	= -476332897260986537L;

	@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH })
	@JoinColumn(name = "parent")
	private Node				parent				= null;

	@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
	private List<Node>			children			= new ArrayList<Node>();

	@OneToMany
	@JoinColumn(name = "node")
	private Set<Voter>			voters				= new HashSet<Voter>();

	@OneToMany
	@JoinColumn(name = "node")
	private Set<ElectionNode>	elections			= new HashSet<ElectionNode>();

	@Transient
	private NodeState			state;

	@Column(name = "state")
	@Enumerated(EnumType.ORDINAL)
	private NodeStateEnum		stateEnum;

	@Column(name = "upToDate")
	private Boolean				upToDate			= true;

	public Node() {
		super();
		this.state = new NodeState(NodeStateEnum.ON);
	}
	
	public Node(NodeType type,String name, String ip, String port) {
		super();
		this.state = new NodeState(NodeStateEnum.ON);
		setNodeType(type);
		setName(name);
		setIp(ip);
		setPort(port);
	}

	public NodeState getState() {
		return state;
	}

	public void setState(NodeState state) {
		this.state = state;
		this.stateEnum = state.getStateEnum();
	}

	public NodeStateEnum getStateEnum() {
		return stateEnum;
	}

	@PostLoad
	public void set() {
		if (stateEnum != null) {
			this.state = new NodeState(stateEnum);
			this.state.setModifiedDate(null);
		}
	}

	public void setStateEnum(NodeStateEnum stateEnum) {
		this.stateEnum = stateEnum;

	}

	public Set<Voter> getVoters() {
		return voters;
	}

	public void setVoters(Set<Voter> voters) {
		this.voters = voters;
	}

	public Set<ElectionNode> getElections() {
		return elections;
	}

	public void setElections(Set<ElectionNode> elections) {
		this.elections = elections;
	}

	public Node getParent() {
		return parent;
	}

	public void setParent(Node node) {
		this.parent = node;
	}

	public List<Node> getChildren() {
		return children;
	}

	public void setChildren(List<Node> children) {
		this.children = children;
	}

	public void addChild(Node node) {
		this.children.add(node);
		node.setParent(this);
		node.setLevel(this.getLevel() + 1);
	}

	public void removeParent() {
		if (this.parent != null) {
			this.parent.getChildren().remove(this);
			ModulesManager.getInstance().updateNode(this.parent);
			this.setParent(null);
		}
	}

	public Boolean getUpToDate() {
		return upToDate;
	}

	public void setUpToDate(Boolean upToDate) {
		this.upToDate = upToDate;
	}
}
